package com.mugui.bean;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.util.TypeUtils;
import com.mugui.Mugui;

/**
 * JsonBean 基本类，使所有继承该bean的实体类可以快速装换
 *
 * @author 木鬼
 */
public abstract class JsonBean implements Mugui, Serializable {
//	static {
//    	ParserConfig.getGlobalInstance().setSafeMode(true);
//	}
    /**
     *
     */
    private static final long serialVersionUID = 8715074045633811373L;

    static {
        ParserConfig globalInstance = ParserConfig.getGlobalInstance();
        globalInstance.putDeserializer(JsonBean.class, new JsonBeanDeserializer(DefaultJsonBean.class));
        SerializeConfig.getGlobalInstance().put(Date.class, new DataSerializer());
        SerializeConfig.getGlobalInstance().put(BigDecimal.class, new DataSerializer());
    }

    {
        ObjectDeserializer objectDeserializer = ParserConfig.getGlobalInstance().get(this.getClass());
        if (objectDeserializer == null)
            ParserConfig.getGlobalInstance().putDeserializer(this.getClass(),
                    new JsonBeanDeserializer(this.getClass()));
    }

    private transient JSONObject __A = null;

    public JSONObject get() {
        if (__A == null)
            __A = toJson();
        Class<?> class1 = getClass();
        do {
            Field[] field = class1.getDeclaredFields();
            for (Field f : field) {
                if (Modifier.isStatic(f.getModifiers())) {
                    continue;
                }
                f.setAccessible(true);
                try {
                    Object object = f.get(this);
                    if (object instanceof JsonBean) {
                        JSONObject jsonObject = ((JsonBean) object).get();
                        if (!jsonObject.isEmpty()) {
                            __A.put(f.getName(), jsonObject);
                        }
                    } else {
                        __A.put(f.getName(), object);
                    }
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        } while ((class1 = class1.getSuperclass()) != JsonBean.class);
        return __A;
    }

    public JsonBean() {
        this(null);
    }

    public JsonBean(JSONObject jsonObject) {
        InitBean(jsonObject);
    }

    public JSONObject toJson() {
        return (JSONObject) JSONObject.toJSON(this);
    }

    /**
     * 自动初始化这个类，只需要传入数据就行
     *
     * @param jsonObject
     * @auther 木鬼
     */
    public void InitBean(JSONObject jsonObject) {
        if (jsonObject == null)
            return;
        if (jsonObject.isEmpty()) {
            return;
        }
        __A = jsonObject;
        Class<?> class1 = getClass();
        do {
            Field[] field = class1.getDeclaredFields();
            for (Field f : field) {
                if (Modifier.isStatic(f.getModifiers())) {
                    continue;
                }
                f.setAccessible(true);
                try {
                    Object object = jsonObject.get(f.getName());
                    if (object != null) {
                        Object cast = TypeUtils.cast(object, f.getType(), ParserConfig.getGlobalInstance());
                        f.set(this, cast);
                    }
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }

            }
        } while ((class1 = class1.getSuperclass()) != JsonBean.class);
    }

    public static <T> T newBean(Class<T> class1, Object object) {
        try {
            Method method = class1.getMethod("InitBean", JSONObject.class);
            T t = null;
            int mod = class1.getModifiers();
            if (class1.getName().contains("$")) {
                if (Modifier.isStatic(mod)) {
                    Constructor<T> constructor = class1.getDeclaredConstructor();
                    constructor.setAccessible(true);
                    t = constructor.newInstance();
                } else {
                    String str[] = class1.getName().split("$");
                    Class<?> father = class1.getClassLoader().loadClass(str[0]);
                    Constructor<?> constructor = father.getDeclaredConstructor();
                    constructor.setAccessible(true);
                    Object father_object = constructor.newInstance();
                    Class<?> class2 = class1.getClassLoader().loadClass(str[0] + "$" + str[1]);
                    constructor = (Constructor<?>) class2.getDeclaredConstructor();
                    constructor.setAccessible(true);
                    Object object2 = constructor.newInstance(father_object);
                    if (class2 == class1) {
                        t = (T) object2;
                    }
                }
            } else
                t = class1.newInstance();
            if (object != null)
                if (object instanceof JsonBean) {
                    method.invoke(t, ((JsonBean) object).get());
                } else {
                    JSONObject parseObject = JSONObject.parseObject(object.toString());
                    method.invoke(t, parseObject);
                }
            return t;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <T extends JsonBean> T newBean(T object) {
        try {
            if (object == null)
                return null;
            Class<? extends JsonBean> class1 = object.getClass();
            JsonBean t = class1.newInstance();
            t.InitBean(((JsonBean) object).get());
            return (T) t;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public String toString() {
        return toJson().toString();
    }

    public Object get(String key) {
        return get().get(key);
    }

    private static HashMap<Class<?>, HashMap<String, Field>> field_hashMap = new HashMap<>();

    public void set(String field_name, Object value) {
        HashMap<String, Field> hashMap = field_hashMap.get(this.getClass());
        if (hashMap == null) {
            synchronized (field_hashMap) {
                hashMap = field_hashMap.get(this.getClass());
                if (hashMap == null) {
                    hashMap = new HashMap<>();
                    List<Field> allField = getAllField(this.getClass());
                    for (Field field : allField) {
                        try {
                            if (!Modifier.isStatic(field.getModifiers()) && !Modifier.isFinal(field.getModifiers())
                                    && !Modifier.isTransient(field.getModifiers()) && !hashMap.containsKey(field.getName())) {
                                field.setAccessible(true);
                                hashMap.put(field.getName(), field);
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    field_hashMap.put(this.getClass(), hashMap);
                }
            }
        }
        Field field = hashMap.get(field_name);
        if (field != null) {
            try {
                if (!field.getType().isAssignableFrom(value.getClass())) {
                    value = TypeUtils.cast(value, field.getType(), ParserConfig.getGlobalInstance());
                }
                field.set(this, value);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (__A == null)
            synchronized (this) {
                __A = toJson();
            }
        __A.put(field_name, value);

    }

    public static List<Field> getAllField(Class<?> cls) {
        List<Field> allFields = new ArrayList<>();
        for (Class<?> currentClass = cls; currentClass != null; currentClass = currentClass.getSuperclass()) {
            Field[] declaredFields = currentClass.getDeclaredFields();
            Collections.addAll(allFields, declaredFields);
        }
        return allFields;
    }
}
